/*
 * Copyright (c) 2003-2010, Live Media Pty. Ltd.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted
 * provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice, this list of
 *     conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright notice, this list of
 *     conditions and the following disclaimer in the documentation and/or other materials
 *     provided with the distribution.
 *  3. Neither the name of Live Media nor the names of its contributors may be used to endorse
 *     or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.colony.concurrent;

import java.util.Stack;

/**
 *  A thread pool.
 */
public class SystemThreadPool
implements ThreadPool, ThreadActivator
{
   protected int _min;   // default 0.
   protected int _max;   // if 0 unlimited.  default 0.
   protected int _threadCount;
   protected Stack _freeThreadPool;
   protected long _timeout;

   private SystemThreadPool()
   {
      _threadCount = 0;
      _freeThreadPool = new Stack();
      _min = 0;
      _max = 0;
      _timeout = 10000;
   }
   
   public int minThreads()
   {
       return _min;
   }

   public void setMinThreads( int m )
   {
      _min = m;       
   } 

   public int maxThreads()
   {
       return _max;
   }

   public void setMaxThreads( int m )
   {
      _max = m;       
   }

   public long threadTimeout()
   {
       return _timeout;
   }

   public void setThreadTimeout( long t )
   {
       _timeout = t;   
   }

   public int threadCount()
   {
       return _threadCount;
   }


   /**
    * This class can only be accessed by the LocalThreadPool class.  This is the global
    * thread pool.  The LocalThreadPool is allowed to actually get the real threads.
    */

   private static ThreadPool _threadPool;

   public static synchronized ThreadPool getThreadPool()
   {
      if ( _threadPool == null )
         _threadPool = new SystemThreadPool();
      return _threadPool;
   }


   public synchronized Worker getThread()
   {
      if ( _freeThreadPool.size() == 0 )
      {
         if ( _threadCount >= _max && _max != 0 )
         {
            return null;  // sorry.. no more threads for you!
         }
         _threadCount++;
         Worker w = new Worker();
         w.setOwner( this, _timeout );
         w.setDaemon( true );
         w.start();
         w.waitStart();
         return w;
      }
      else 
      {
         return (Worker) _freeThreadPool.pop();
      }
   }

   public synchronized void returnThread( Worker w )
   {
      w.setOwner( this, _timeout );
      _freeThreadPool.push( w );
   }

   public synchronized void workerTimeout( Worker w )
   {
      if ( _threadCount > _min )
      {
         _threadCount--;
         _freeThreadPool.remove( w );
         w.stopWorker();
      }
   }

   public boolean assignThread( Runnable worker )
   {
	   	Worker w = getThread();
	   	if ( w != null )
	   	{
	   		w.activate( worker );
	   		return true;
	   	}
	   	return false;
   }

}